/**
 * Copyright (C) 2011 Vinicius Vielmo Cogo, Marcelo Pasin, and the authors
 * indicated in the @author tags.
 * 
 * This file is part of DiversityAgent.
 * 
 * DiversityAgent is a free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 * 
 * DiversityAgent is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with DiversityAgent. If not, see <http://www.gnu.org/licenses/>.
 */
package diversities;

import java.util.ArrayList;
import java.util.Properties;

import diversity_agent.Cloud;
import diversity_agent.DataContainer;

/**
 * 
 * @author Vinicius Vielmo Cogo (vielmo at lasige.di.fc.ul.pt)
 * @version 0.1-beta
 * @since 2011-11-18
 * 
 */
public class CloudProvider extends diversity_agent.Diversity
{

	private int	mLastCloudUsed;

	/**
	 * 
	 */
	public CloudProvider()
	{
		mDiversityAxis = diversity_agent.DIVERSITY_AXIS.ADMINISTRATIVE;
		mLastCloudUsed = -1;
	}

	@Override
	public Properties getContribution(Properties theProperties,
			DataContainer theDataContainer)
	{
		// Verifying if the cloud wasn't already chosen
		if (theProperties.getProperty("cloud.name") == null) {
			diversity_agent.Image aImage = null;
			ArrayList<String> aCloudsRelated = null;
			if (theProperties.getProperty("disk.image.name") != null) {
				aImage = theDataContainer.retrieveImage(theProperties
						.getProperty("disk.image.name"));
				aCloudsRelated = aImage.getAllocatedClouds();
			}

			// Getting all registered clouds
			ArrayList<Cloud> aClouds = theDataContainer.retrieveClouds();

			int aRunningVMs = Integer.MAX_VALUE;
			int aCreatedVMs = Integer.MAX_VALUE;
			int aWinnerIndex = -1;

			// [TODO] Allow the usage of the cloud_policy property
			// String aPolicy = theProperties.getProperty("cloud_policy");
			String aPolicy = "round_robin";

			if (aClouds.size() <= 0) {
				System.out
						.println("[ERROR     ] There is no cloud associated with your service.");
				System.out
						.println("[SOLUTION  ] Please, create at least one cloud before creating virtual machines.");
				return theProperties;
			}

			if (aPolicy.equals("round_robin")) {
				aWinnerIndex = (++mLastCloudUsed) % aClouds.size();
			} else if (aPolicy.equals("current_usage")) {
				for (int i = 0 ; i < aClouds.size() ; i++) {
					if (aClouds.get(i).countRunningVms() < aRunningVMs
							&& !aClouds.get(i).isBlocked()
							&& aCloudsRelated.contains(aClouds.get(i)
									.getCloudName())) {
						aRunningVMs = aClouds.get(i).countRunningVms();
						aWinnerIndex = i;
					}
				}
			} else if (aPolicy.equals("historical_usage")) {
				for (int i = 0 ; i < aClouds.size() ; i++) {
					if (aClouds.get(i).countCreatedVms() < aCreatedVMs
							&& !aClouds.get(i).isBlocked()
							&& aCloudsRelated.contains(aClouds.get(i)
									.getCloudName())) {
						aCreatedVMs = aClouds.get(i).countCreatedVms();
						aWinnerIndex = i;
					}
				}
			}

			if (aWinnerIndex == -1) {
				theProperties.setProperty("cloud.name", aCloudsRelated.get(0));
			} else {
				// Adding the property
				theProperties.setProperty("cloud.name", aClouds.get(
						aWinnerIndex).getCloudName());
			}

			mLastCloudUsed = aWinnerIndex;
		}

		// Returning the set of properties
		return theProperties;
	}
}
